package asteroids.model.programs.parsing;

import asteroids.model.programs.*;
import asteroids.statement.*;
import asteroids.*;
import java.util.List;
import asteroids.expression.*;

public class ProgramFactoryImpl<E, S, T> implements ProgramFactory<E, S, T> {

	@Override
	public E createDoubleLiteral(int line, int column, double d) {
		return (E) new asteroids.expression.DoubleLiteral(d);
	}

	@Override
	public E createBooleanLiteral(int line, int column, boolean b) {
		return (E) new asteroids.expression.BooleanLiteral(b);
	}

	@Override
	public E createAnd(int line, int column, E e1, E e2) {
		return (E) new And((Expression) e1, (Expression) e2);
	}

	@Override
	public E createOr(int line, int column, E e1, E e2) {
		return (E) new Or((Expression) e1, (Expression) e2);
	}

	@Override
	public E createNot(int line, int column, E e) {
		return (E) new Not((Expression) e);
	}

	@Override
	public E createNull(int line, int column) {
		return (E) new asteroids.expression.EntityExpression();
	}

	@Override
	public E createSelf(int line, int column) {
		return (E) new SelfExpression();
	}

	@Override
	public E createGetX(int line, int column, E e) {
		return (E) new asteroids.expression.GetXPosExpression(((Expression) e));
	}

	@Override
	public E createGetY(int line, int column, E e) {
		return (E) new asteroids.expression.GetYPosExpression(((Expression) e));
	}

	@Override
	public E createGetVX(int line, int column, E e) {
		return (E) new asteroids.expression.GetXVelExpression(((Expression) e));
	}

	@Override
	public E createGetVY(int line, int column, E e) {
		return (E) new asteroids.expression.GetYVelExpression(((Expression) e));
	}

	@Override
	public E createGetRadius(int line, int column, E e) {
		return (E) new asteroids.expression.GetRadiusExpression(
				((Expression) e));
	}

	@Override
	public E createVariable(int line, int column, String name) {
		if (name == null)
			name = "";
		return (E) new asteroids.expression.Variable(name);
	}

	@Override
	public E createLessThan(int line, int column, E e1, E e2) {
		return (E) new Smaller((Expression) e1, (Expression) e2);
	}

	@Override
	public E createGreaterThan(int line, int column, E e1, E e2) {
		return (E) new Greater((Expression) e1, (Expression) e2);
	}

	@Override
	public E createLessThanOrEqualTo(int line, int column, E e1, E e2) {
		return (E) new SmallerEqual((Expression) e1, (Expression) e2);
	}

	@Override
	public E createGreaterThanOrEqualTo(int line, int column, E e1, E e2) {
		return (E) new GreaterEqual((Expression) e1, (Expression) e2);
	}

	@Override
	public E createEquality(int line, int column, E e1, E e2) {
		return (E) new Equal((Expression) e1, (Expression) e2);
	}

	@Override
	public E createInequality(int line, int column, E e1, E e2) {
		return (E) new NotEqual((Expression) e1, (Expression) e2);
	}

	@Override
	public E createAdd(int line, int column, E e1, E e2) {
		return (E) new Addition((Expression) e1, (Expression) e2);
	}

	@Override
	public E createSubtraction(int line, int column, E e1, E e2) {
		return (E) new Subtraction((Expression) e1, (Expression) e2);
	}

	@Override
	public E createMul(int line, int column, E e1, E e2) {
		return (E) new Multiplication((Expression) e1, (Expression) e2);
	}

	@Override
	public E createDivision(int line, int column, E e1, E e2) {
		return (E) new Division((Expression) e1, (Expression) e2);
	}

	@Override
	public E createSqrt(int line, int column, E e) {
		return (E) new SquareRoot((Expression) e);
	}

	@Override
	public E createGetDirection(int line, int column) {
		return (E) new GetDirectionExpression();
	}

	@Override
	public E createSin(int line, int column, E e) {
		return (E) new Sine((Expression) e);
	}

	@Override
	public E createCos(int line, int column, E e) {
		return (E) new Cosine((Expression) e);
	}

	@Override
	public S createEnableThruster(int line, int column) {
		return (S) new ThrustStatement();
	}

	@Override
	public S createDisableThruster(int line, int column) {
		return (S) new ThrustOffStatement();
	}

	@Override
	public S createFire(int line, int column) {
		return (S) new FireStatement();
	}

	@Override
	public S createTurn(int line, int column, E angle) {
		return (S) new TurnStatement((Expression) angle);
	}

	@Override
	public S createAssignment(int line, int column, String variable, E rhs) {
		return (S) new AssignStatement(variable, (Expression) rhs);

	}

	@Override
	public S createIf(int line, int column, E condition, S then, S otherwise) {
		return (S) new IfElseStatement((Expression) condition,
				(Statement) then, (Statement) otherwise);
	}

	@Override
	public S createWhile(int line, int column, E condition, S body) {
		return (S) new WhileStatement((Expression) condition, (Statement) body);
	}

	@Override
	public S createForeach(int line, int column,
			asteroids.model.programs.parsing.ProgramFactory.ForeachType type,
			String variableName, S body) {
		return (S) new ForEachStatement(type, variableName, (Statement) body);
	}

	@Override
	public S createSkip(int line, int column) {
		return (S) new SkipStatement();
	}

	@Override
	public S createSequence(int line, int column, List<S> statements) {
		int i = 0;
		boolean ok = true;
		if (statements.size() == 0)
			return (S) new SeqStatement();
		while (i < statements.size()) {
			if (!(statements.get(i) instanceof Statement))
				ok = false;
			i++;
		}
		if (ok) {
			S temp1 = statements.get(0);
			Statement oud = (Statement) temp1;
			Statement nieuw = new SkipStatement();
			i = 1;
			while (i < statements.size()) {
				S temp = statements.get(i);
				Statement join = (Statement) temp;
				nieuw = new SeqStatement(oud, join);
				oud = nieuw;
				i++;
			}
			return (S) nieuw;
		} else
			return (S) new SkipStatement();

	}

	@Override
	public S createPrint(int line, int column, E e) {
		if (e instanceof Expression)
			return (S) new Print((Expression) e);
		else
			return (S) new SkipStatement();
	}

	@Override
	public T createDoubleType() {
		return (T) new NumericExpression();
	}

	@Override
	public T createBooleanType() {
		return (T) new BooleanExpression();
	}

	@Override
	public T createEntityType() {
		return (T) new EntityExpression();
	}

}
